#include "v4a_hal.h"
#include <fcntl.h>
#include "spi.h"
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <linux/ioctl.h>
//#include <linux/i2c.h>
//#include <linux/i2c-dev.h>
int spi_fd;
int i2c_fd;
#define I2C_RETRIES   0x0701
#define I2C_TIMEOUT   0x0702
#define I2C_SLAVE     0x0703       //IIC从器件的地址设置
#define I2C_BUS_MODE   0x0780
#define	 I2C_TENBIT 	0x0704

struct spi_data gdata;
struct spi_buffer tx_buf;

#define TXNEG 0
#define RXNEG 1

#define SpiSelectCS0()				ioctl(spi_fd, SPI_IOC_SELECTSLAVE, 0)
#define SpiDeselectCS0()			ioctl(spi_fd, SPI_IOC_SELECTSLAVE, 1)

int	vramaddr;

LAYERMIXER v4a_gmixer;
HDPLOADER v4a_gploader;

IMGNODE bkgnd_fbcopy;
IMGNODE bkgnd_fbdisplay;
IMGNODE overlay_fbcopy;
IMGNODE overlay_fbdisplay;
IMGNODE flex_fbdisplay;

GUIPOINT *gui_point(int x,int y)
{
	static GUIPOINT p;
	p.x = x;
	p.y = y;

	return &p;
}

GUIRECT *gui_rect(int x,int y,int xlen,int ylen)
{
	static GUIRECT rect;
	rect.lvertex.x = x;
	rect.lvertex.y = y;
	rect.width = xlen;
	rect.height = ylen;

	return &rect;
}

IMGNODE *img_node(int base,int bpp,int index,int xlen,int ylen)
{
	static IMGNODE node;
	node.img_base = base;
	node.img_bpp = bpp;
	node.img_xlen = xlen;
	node.img_ylen = ylen;
	node.index = index;
	return &node;
}


int v4a_initial()
{
	spi_fd = open("/dev/spi0", O_RDWR);
	if ( spi_fd < 0) {
		printf("Initial V4A HAL Error!\n");
		return -1;
	}

//	i2c_fd = open("/dev/i2c0", O_RDWR);
//	if(i2c_fd < 0)
//		printf("open i2c failed\n\n\n\n\n\n\n\n\n\n\n\n");
//		return -1;
//
//	ioctl(i2c_fd,I2C_TENBIT,0);   //not 10bit
//
//	ioctl(i2c_fd,I2C_SLAVE,0x3c);

	struct spi_parameter para;

	para.divider = 1;
	para.active_level = 0;
	para.tx_neg = TXNEG;				// Tx: falling edge, Rx: rising edge
	para.rx_neg = RXNEG;
	para.lsb = 0;
	para.sleep = 0;

	ioctl(spi_fd, SPI_IOC_SETPARAMETER, &para);
	ioctl(spi_fd, SPI_IOC_GETPARAMETER, &para);
	if(para.divider != 1
	|| para.active_level != 0
	|| para.tx_neg != TXNEG
	|| para.rx_neg != RXNEG
	|| para.lsb != 0
	|| para.sleep != 0)
	{
		printf("Set V4A Parameter Faild!\n");
		return -1;
	}
	vramaddr = 0;

	//
	v4a_gmixer.outenable = 0;
	v4a_gmixer.enable.enable_value = 0;
	bkgnd_fbdisplay.img_base = V4A_BKGNDBASE0;
	bkgnd_fbcopy.img_base = V4A_BKGNDBASE1;
	overlay_fbdisplay.img_base = V4A_OVERLAYBASE0;
	overlay_fbcopy.img_base = V4A_OVERLAYBASE1;
	flex_fbdisplay.img_base = V4A_FLEXBASE;
	return 1;
}

void v4a_setregs(int addr,int length,int *regs)
{
	tx_buf.tx_buffer[0] = CSR_WRITE<< 24 | (addr & 0xff) << 16 | (length & 0xff) << 8;
	memcpy(&tx_buf.tx_buffer[1],regs,sizeof(int)*length);
	tx_buf.tx_length = length + 1;
	SpiSelectCS0();
	ioctl(spi_fd,SPI_IOC_TRANSITBUF,&tx_buf);
	SpiDeselectCS0();

}

void v4a_getregs(int addr,int length,int *regs)
{

}

int v4a_getstatus()
{
	char idaddr = 0;
	char statusaddr = 0xf0;
	char resp[4];
	int status = 1;

	while(status > 0)
	{
	ioctl(spi_fd,SPI_IOC_GETSTATUS,&status);
	if((status & 0x80000000) == 0)
		system("reboot");
	//printf("status = %x\n",status);
	status &= 0x10;

	}
//	printf("process complete\n");
//	//printf("status = %x\n",status & 0x10);
	return 0;
	//return 0;
	//return ((gdata.read_data & 0xff) != 0x26);
}

void v4a_fillvram(int addr,int length,int *buffer)
{
	int	once_len;
	int	transpoint = 0;
	once_len = 255;
	while(length > 0)
	{
		tx_buf.tx_buffer[0] = DAT_WRITE<< 24 | (((addr>>2) + transpoint) & 0x00ffffff);

		length -= once_len;

		memcpy(&tx_buf.tx_buffer[1],&buffer[transpoint],sizeof(int)*once_len);
		transpoint += once_len;
		tx_buf.tx_length = (once_len + 1) ;

		SpiSelectCS0();

		ioctl(spi_fd,SPI_IOC_TRANSITBUF,&tx_buf);

		SpiDeselectCS0();
	}
}

//void v4a_fillvram(int addr,int length,int *buffer)
//{
//	int	once_len;
//	int	transpoint = 0;
//	tx_buf.tx_buffer[0] = DAT_WRITE<< 24 | ((addr>>2) & 0x00ffffff);
//	if(length >= 255)
//		once_len = 255;
//	else if(length % 4 == 3)
//		once_len = length;
//	else
//		once_len = (length / 4) * 4 -1;
//
//	length -= once_len;
//
//	memcpy(&tx_buf.tx_buffer[1],buffer,sizeof(int)*once_len);
//	transpoint += once_len;
//	tx_buf.tx_length = (once_len + 1) ;
//	SpiSelectCS0();
//
//	ioctl(spi_fd,SPI_IOC_TRANSITBUF,&tx_buf);
//	while(length > 0)
//	{
//		if(length >= 256)
//			once_len = 256;
//		else if(length % 4 == 0)
//			once_len = length;
//		else if(length > 3)
//			once_len = (length / 4) * 4;
//		else once_len = 1;
//		length -= once_len;
//		memcpy(tx_buf.tx_buffer,&buffer[transpoint],sizeof(int)*once_len);
//		transpoint += once_len;
//		tx_buf.tx_length = once_len;
//		ioctl(spi_fd,SPI_IOC_TRANSITBUF,&tx_buf);
//	}
//
//	SpiDeselectCS0();
//}
/*int	v4a_drawrect(IMGNODE *node,GUIRECT *rect,COLOR c)
{
	v4a_gploader.ctrl.ctrl_reg.start = 0;
	v4a_gploader.ctrl.ctrl_reg.clear = 1;
	v4a_setregs(HDPLOADERBASE,sizeof(HDPLOADER)/4,(int *)&v4a_gploader);
	v4a_gploader.ctrl.ctrl_reg.clear = 0;
	v4a_setregs(HDPLOADERBASE,sizeof(HDPLOADER)/4,(int *)&v4a_gploader);
	if(node->img_bpp == 16)
	{
		v4a_gploader.source_width = rect->width/2;
		v4a_gploader.sink_width = node->img_xlen/2;
		v4a_gploader.sink_xstart = rect->lvertex.x/2;
		v4a_gploader.load_xlength = rect->width/2;
		v4a_gploader.load_filldata = TCOLOR(c) + (TCOLOR(c) << 16);
	}
	else if(node->img_bpp == 32)
	{
		v4a_gploader.source_width = rect->width;
		v4a_gploader.sink_width = node->img_xlen;
		v4a_gploader.sink_xstart = rect->lvertex.x;
		v4a_gploader.load_xlength = rect->width;
		v4a_gploader.load_filldata = c;
	}
	else
		return ERR_FMT;
	v4a_gploader.source_height = rect->height;
	v4a_gploader.sink_height = node->img_ylen;;
	v4a_gploader.source_xstart = 0;
	v4a_gploader.source_ystart = 0;
	v4a_gploader.sink_ystart = rect->lvertex.y;
	v4a_gploader.load_ylength = rect->height;
	v4a_gploader.format.format_reg.fill_mode = 1;
	v4a_gploader.format.format_reg.source_order = 0;
	v4a_gploader.ctrl.ctrl_reg.start = 1;
	v4a_gploader.sink_base_address = node->img_base;
	v4a_gploader.source_base_address = 0;

	v4a_setregs(HDPLOADERBASE,sizeof(HDPLOADER)/4,(int *)&v4a_gploader);

	while(v4a_getstatus() & V4ABUSY)
		usleep(1000);
	return 0;
}
*/

int	v4a_drawrect(IMGNODE *node,GUIRECT *rect,COLOR c)
{


	v4a_gploader.ctrl.ctrl_reg.start = 0;
	v4a_gploader.ctrl.ctrl_reg.clear = 1;
	v4a_setregs(HDPLOADERBASE,sizeof(HDPLOADER)/4,(int *)&v4a_gploader);
	v4a_gploader.ctrl.ctrl_reg.clear = 0;
	v4a_setregs(HDPLOADERBASE,sizeof(HDPLOADER)/4,(int *)&v4a_gploader);
	if(node->img_bpp == 16)
	{
		v4a_gploader.source_width = rect->width/2;
		v4a_gploader.sink_width = node->img_xlen/2;
		v4a_gploader.sink_xstart = rect->lvertex.x/2;
		v4a_gploader.load_xlength = rect->width/2;
		v4a_gploader.load_filldata = TCOLOR(c) + (TCOLOR(c) << 16);
	}
	else if(node->img_bpp == 32)
	{
		v4a_gploader.source_width = rect->width;
		v4a_gploader.sink_width = node->img_xlen;
		v4a_gploader.sink_xstart = rect->lvertex.x;
		v4a_gploader.load_xlength = rect->width;
		v4a_gploader.load_filldata = c;
	}
	else
		return ERR_FMT;
	v4a_gploader.source_height = rect->height;
	v4a_gploader.sink_height = node->img_ylen;;
	v4a_gploader.source_xstart = 0;
	v4a_gploader.source_ystart = 0;
	v4a_gploader.sink_ystart = rect->lvertex.y;
	v4a_gploader.load_ylength = rect->height;
	v4a_gploader.format.format_reg.fill_mode = 1;
	v4a_gploader.format.format_reg.source_order = 0;
	v4a_gploader.ctrl.ctrl_reg.start = 1;
	v4a_gploader.sink_base_address = node->img_base;
	v4a_gploader.source_base_address = 0;

	v4a_setregs(HDPLOADERBASE,sizeof(HDPLOADER)/4,(int *)&v4a_gploader);

	while(v4a_getstatus() != 0)
	{
		usleep(100);
	}
		//usleep(1000);
	return 0;
}

int	v4a_showimage(IMGNODE *node,LAYER *lp,GUIPOINT *p)
{

	return v4a_showimagecut(node,lp,gui_rect(0,0,node->img_xlen,node->img_ylen),p);

}

int	v4a_showimagecut(IMGNODE *node,LAYER *lp,GUIRECT *src_rect,GUIPOINT *sink_p)
{

	return v4a_copyimagecut(node,img_node(lp->vrambase,lp->bpp,0,lp->virtual_xlen,lp->virtual_ylen),src_rect,sink_p);

}


int	v4a_copyimage(IMGNODE *src,IMGNODE *sink,GUIPOINT *p)
{

	return v4a_copyimagecut(src,sink,gui_rect(0,0,src->img_xlen,src->img_ylen),p);

}

int	v4a_copyimagecut(IMGNODE *src,IMGNODE *sink,GUIRECT *src_rect,GUIPOINT *sink_p)
{
	v4a_gploader.ctrl.ctrl_reg.start = 0;
	v4a_gploader.ctrl.ctrl_reg.clear = 1;
	v4a_setregs(HDPLOADERBASE,sizeof(HDPLOADER)/4,(int *)&v4a_gploader);
	v4a_gploader.ctrl.ctrl_reg.clear = 0;
	v4a_setregs(HDPLOADERBASE,sizeof(HDPLOADER)/4,(int *)&v4a_gploader);

	if(sink->img_bpp != src->img_bpp)
		return ERR_BWM;
	if(src->img_bpp == 16)
	{
		v4a_gploader.source_width = src->img_xlen/2;
		v4a_gploader.sink_width = sink->img_xlen/2;
		v4a_gploader.sink_xstart = sink_p->x/2;
		v4a_gploader.load_xlength = src_rect->width/2;
		v4a_gploader.source_xstart = src_rect->lvertex.x/2;
	}
	else if(src->img_bpp == 32)
	{
		v4a_gploader.source_width = src->img_xlen;
		v4a_gploader.sink_width = sink->img_xlen;
		v4a_gploader.sink_xstart = sink_p->x;
		v4a_gploader.load_xlength = src_rect->width;
		v4a_gploader.source_xstart = src_rect->lvertex.x;
	}
	else
		return ERR_FMT;
	v4a_gploader.source_height = src->img_ylen;
	v4a_gploader.sink_height = sink->img_ylen;
	v4a_gploader.source_ystart = src_rect->lvertex.y;
	v4a_gploader.sink_ystart = sink_p->y;
	v4a_gploader.load_ylength = src_rect->height;
	v4a_gploader.format.format_reg.fill_mode = 0;
	v4a_gploader.format.format_reg.source_order = 0;
	v4a_gploader.ctrl.ctrl_reg.start = 1;
	v4a_gploader.sink_base_address = sink->img_base;
	v4a_gploader.source_base_address = src->img_base;

	v4a_setregs(HDPLOADERBASE,sizeof(HDPLOADER)/4,(int *)&v4a_gploader);

	//printf("wait processing \n");
	//system("/mnt/nand1-2/mplayer");
	while(v4a_getstatus() != 0)
	{
		usleep(100);
	}
		//usleep(1000);
	return 0;
}

void v4a_initscreen(int xlength,int ylength)
{
	v4a_gmixer.screen_xlength = xlength;
	v4a_gmixer.screen_ylength = ylength;
	background.bpp = 16;
	background.layer = 0;
	background.virtual_xlen = xlength;
	background.virtual_ylen = ylength;
	background.virtual_xoffset = 0;
	background.virtual_yoffset = 0;
	background.screen_xlen = xlength;
	background.screen_ylen = ylength;
	background.screen_xoffset = 0;
	background.screen_yoffset = 0;
	background.enable = 0;
	background.auto_scroll = 0;
	background.vrambase = bkgnd_fbdisplay.img_base;
	bkgnd_fbdisplay.img_bpp = 16;
	bkgnd_fbdisplay.img_xlen = xlength;
	bkgnd_fbdisplay.img_ylen = ylength;
	bkgnd_fbcopy.img_bpp = 16;
	bkgnd_fbcopy.img_xlen = xlength;
	bkgnd_fbcopy.img_ylen = ylength;
	overlay.bpp = 32;
	overlay.layer = 0;
	overlay.virtual_xlen = xlength;
	overlay.virtual_ylen = ylength;
	overlay.virtual_xoffset = 0;
	overlay.virtual_yoffset = 0;
	overlay.screen_xlen = xlength;
	overlay.screen_ylen = ylength;
	overlay.screen_xoffset = 0;
	overlay.screen_yoffset = 0;
	overlay.enable = 0;
	overlay.auto_scroll = 0;
	overlay.vrambase = overlay_fbdisplay.img_base;
	overlay_fbdisplay.img_bpp = 32;
	overlay_fbdisplay.img_xlen = xlength;
	overlay_fbdisplay.img_ylen = ylength;
	overlay_fbcopy.img_bpp = 32;
	overlay_fbcopy.img_xlen = xlength;
	overlay_fbcopy.img_ylen = ylength;
	v4a_gmixer.setting = 1;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
	v4a_gmixer.setting = 0;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
}

void v4a_enablescreen(int enable)
{
	unsigned int vout_8bit = LCD_CLK;

	v4a_gmixer.outenable = (enable & 1) | ((vout_8bit & 1) << 1);
	printf("vout_8bit=%d\nv4a_gmixer.outenable=%d\n",vout_8bit,v4a_gmixer.outenable);
	v4a_gmixer.setting = 1;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
	v4a_gmixer.setting = 0;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
}

void v4a_displaybkgnd(int enable)
{
	v4a_gmixer.enable.enablelist.v0_enable = enable & 1;
	v4a_gmixer.v0_baseaddr = bkgnd_fbdisplay.img_base;
	v4a_gmixer.setting = 1;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
	v4a_gmixer.setting = 0;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
}

void v4a_switchbkgnd()
{
	unsigned baseaddr = bkgnd_fbcopy.img_base;
	bkgnd_fbcopy.img_base = bkgnd_fbdisplay.img_base;
	bkgnd_fbdisplay.img_base = baseaddr;
	v4a_gmixer.v0_baseaddr = baseaddr;
	background.vrambase = baseaddr;
	v4a_gmixer.setting = 1;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
	v4a_gmixer.setting = 0;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
}

void v4a_setvideoarea(GUIRECT *rect)
{

	v4a_gmixer.v1_xlength = rect->width;
	v4a_gmixer.v1_ylength = rect->height;
	v4a_gmixer.v1_xstart = rect->lvertex.x;
	v4a_gmixer.v1_ystart = rect->lvertex.y;
	video.virtual_xlen = 1024;
	video.virtual_ylen = 600;
	video.virtual_xoffset = 0;
	video.virtual_yoffset = 0;
	video.vrambase = V4A_VIDEOBASE;
	video.screen_xlen = rect->width;
	video.screen_ylen = rect->height;
	video.screen_xoffset = rect->lvertex.x;
	video.screen_yoffset = rect->lvertex.y;
	video.layer = 1;
	video.bpp = 16;
	video.auto_scroll = 0;
	v4a_gmixer.setting = 1;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
	v4a_gmixer.setting = 0;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);

}

void v4a_displayvideo(int enable)
{
	v4a_gmixer.enable.enablelist.v1_enable = enable & 1;
	printf("video xlength = %d\nvideo ylength = %d \nvideo xstart = %d \nvideo ystart = %d",v4a_gmixer.v1_xlength,v4a_gmixer.v1_ylength,v4a_gmixer.v1_xstart,v4a_gmixer.v1_ystart);
	v4a_gmixer.setting = 1;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
	v4a_gmixer.setting = 0;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
	//add pause command here
}

void v4a_displayoverlay(int enable)
{

	v4a_gmixer.enable.enablelist.v2_enable = enable & 1;
	v4a_gmixer.v2_baseaddr = overlay_fbdisplay.img_base;
	v4a_gmixer.setting = 1;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
	v4a_gmixer.setting = 0;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
}

void v4a_switchoverlay()
{
	unsigned baseaddr = overlay_fbcopy.img_base;
	overlay_fbcopy.img_base = overlay_fbdisplay.img_base;
	overlay_fbdisplay.img_base = baseaddr;
	v4a_gmixer.v2_baseaddr = baseaddr;
	overlay.vrambase = baseaddr;
	v4a_gmixer.setting = 1;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
	v4a_gmixer.setting = 0;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
}

void v4a_displayflex(int enable)
{
	v4a_gmixer.enable.enablelist.v3_enable = enable & 1;
	v4a_gmixer.v3_baseaddr = flex_fbdisplay.img_base;
	v4a_gmixer.setting = 1;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
	v4a_gmixer.setting = 0;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
}

void v4a_setautoscroll(int enable,int dir,int speed,int step)
{
	if(!enable || speed == 0 || step == 0)
		v4a_gmixer.scrollparam = 0;
	else
		v4a_gmixer.scrollparam = ((enable & 0x1) << 14) + ((dir & 0x3) << 12) + ((speed & 0x3f) << 6) + (step & 0x3f);
	v4a_gmixer.setting = 0;
	v4a_setregs(LAYERMIXERBASE,sizeof(LAYERMIXER)/4,(int *)&v4a_gmixer);
}

void v4a_setflexarea(GUIRECT *vrect,GUIRECT *orect)
{
	v4a_gmixer.v3_oxstart = orect->lvertex.x;
	v4a_gmixer.v3_oystart = orect->lvertex.y;
	v4a_gmixer.v3_oxlength = orect->width;
	v4a_gmixer.v3_oylength = orect->height;
	v4a_gmixer.v3_vxlength = vrect->width;
	v4a_gmixer.v3_vylength = vrect->height;
	v4a_gmixer.v3_vxstart = vrect->lvertex.x;
	v4a_gmixer.v3_vystart = vrect->lvertex.y;
	flex_fbdisplay.img_xlen = vrect->width;
	flex_fbdisplay.img_ylen = vrect->height;
	flex_fbdisplay.img_bpp = 32;
}

